package com.swak.job.aspect;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;

import com.swak.annotation.job.DelayJobEvent;
import com.swak.asm.FieldCache;
import com.swak.asm.FieldCache.ClassMeta;
import com.swak.asm.FieldCache.FieldMeta;
import com.swak.job.JobManager;
import com.swak.utils.StringUtils;
import com.swak.utils.time.DateTimes;

@Aspect
public class DelayJobEventAspect implements Ordered {

	@Autowired
	private JobManager jobManager;

	/**
	 * 拦截刪除緩存
	 */
	@Pointcut("@annotation(com.swak.annotation.job.DelayJobEvent)")
	public void DelayJobEvent_Pointcut_Interceptor() {
	}

	/**
	 * 拦截器处理方法
	 * 
	 * @param point
	 * @return
	 * @throws Throwable
	 */
	@Around("DelayJobEvent_Pointcut_Interceptor()")
	public Object around(ProceedingJoinPoint point) throws Throwable {
		Object result = point.proceed();
		Method method = ((MethodSignature) point.getSignature()).getMethod();
		DelayJobEvent delayJobEvent = method.getAnnotation(DelayJobEvent.class);
		if (result != null && delayJobEvent != null) {
			ClassMeta classMeta = FieldCache.checkAndSet(result.getClass());
			FieldMeta configFieldMeta = StringUtils.isNotBlank(delayJobEvent.configField())
					? classMeta.getField(delayJobEvent.configField())
					: null;
			if (delayJobEvent.delayTimeMs() > 0 || StringUtils.isNotBlank(delayJobEvent.delayTimeField())) {
				Object configValue = configFieldMeta != null ? configFieldMeta.getFieldValue(result)
						: StringUtils.EMPTY;
				FieldMeta delayTimeFieldMeta = StringUtils.isNotBlank(delayJobEvent.delayTimeField())
						? classMeta.getField(delayJobEvent.delayTimeField())
						: null;
				LocalDateTime delayTime = delayJobEvent.delayTimeMs() > 0
						? DateTimes.setExpired(DateTimes.now(), delayJobEvent.delayTimeMs())
						: null;
				if (delayTime == null && delayTimeFieldMeta != null) {
					Object delayTimeValue = delayTimeFieldMeta.getFieldValue(result);
					if (delayTimeValue != null && delayTimeValue instanceof LocalDateTime) {
						delayTime = (LocalDateTime) delayTimeValue;
					}
				}

				if (StringUtils.isNotBlank(delayJobEvent.job()) && configValue != null && delayTime != null) {
					jobManager.dispatch(delayJobEvent.job(), String.valueOf(configValue), delayTime);
				}
			}
		}
		return result;
	}

	/**
	 * Aop的顺序要早于spring的事务
	 * 注意Order序号要小于{@link org.springframework.aop.interceptor.ExposeInvocationInterceptor},
	 * PriorityOrdered.HIGHEST_PRECEDENCE + 1
	 */
	@Override
	public int getOrder() {
		return Ordered.HIGHEST_PRECEDENCE;
	}
}
